﻿package  {
	
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	
	import flash.system.fscommand;
	
	public class Tetris extends MovieClip {
		private var game_lvl:int = 1;
		private var game_scr:int = 0;
		
		private var game_pause_flag:Boolean = false;
		private var game_enterframe_count:int = 0;
		
		private const mainPanelX = -13.9;
		private const mainPanelY = -1.75;
		
		private const xLeft = 235;
		private const yTop = 8;
		private const yBottom = 549 - mainPanelY;
		private const cellWidth = 30;
		
		private const cellRowNum = int(420 / cellWidth);
		private const cellLineNum = int(540 / cellWidth);
		private const midNum =  int(cellRowNum / 2);
		
		private var cellArr:Array;
		
		private var mainPanel;
		private var helpPanel;
		private var endPanel;
		
		private var shape = new Shape_Preview();
		private const shapeX = 100 - mainPanelX;
		private const shapeY = 161.35 - mainPanelY;
		private const shapeTotalNum = 7;
		
		private var crtShapeIndex:uint;
		private var nextShapeIndex:uint;
		private var crtRollIndex:uint;
		private var newShapeFlag:Boolean = true;
		
		private var cell1:Cell;
		private var cell2:Cell;
		private var cell3:Cell;
		private var cell4:Cell;
		
		private var gameOverFlag:Boolean = false;
		
		private var bgmSound:Sound;
		private var soundChannel:SoundChannel;
		private var isQuiet:Boolean = false;
		private var dropSound:Sound;
		private var removeSound:Sound;
		
		public function Tetris() {
			init();
		}
		
		private function init(){
			bgmSound = new bgm();
			soundChannel = bgmSound.play(0, 10000, new SoundTransform(0.2, 0));
			
			dropSound = new drop();
			removeSound = new remove();
			
			mainPanel = new MainPanel();
			this.addChild(mainPanel);
			mainPanel.x = mainPanelX;
			mainPanel.y = mainPanelY;
			
			mainPanel.addChild(shape);
			shape.x = shapeX;
			shape.y = shapeY;
			shape.visible = false;
			
			mainPanel.sound_btn.addEventListener(MouseEvent.CLICK, soundBtnHandler);
			mainPanel.quiet_btn.addEventListener(MouseEvent.CLICK, quietBtnHandler);
			
			mainPanel.close_btn.addEventListener(MouseEvent.CLICK, quitHandler);
			
			cellArr = new Array();
			
			for(var i:int = 0; i < cellRowNum; i ++){
				cellArr[i] = new Array();
				for(var j:int = 0; j < cellLineNum; j ++){
					var cell = new Cell(i, j);
					mainPanel.addChild(cell);
					
					cell.x = xLeft - mainPanelX + i * cellWidth;
					cell.y = yBottom - (j + 1) * cellWidth;
					
					cellArr[i][j] = cell;
				}
			}
			
			helpPanel = new HelpPanel();
			this.addChild(helpPanel);
			helpPanel.x = xLeft;
			helpPanel.y = yTop;
			helpPanel.go_btn.addEventListener(MouseEvent.CLICK, goBtnHandler);
			
			endPanel = new EndPanel();
			this.addChild(endPanel);
			endPanel.x = xLeft;
			endPanel.y = yTop;
			endPanel.retry_btn.addEventListener(MouseEvent.CLICK, retryBtnHandler);
			endPanel.visible = false;
			
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

			restart();
		}
		
		private function restart(){
			game_lvl = 1;
			game_scr = 0;
			
			mainPanel.level_txt.text = game_lvl;
			mainPanel.score_txt.text = game_scr;
			
			crtShapeIndex = int(Math.random() * shapeTotalNum) + 1;
			shape.gotoAndStop(crtShapeIndex);
			
			for(var i:int = 0; i < cellRowNum; i ++){
				for(var j:int = 0; j < cellLineNum; j ++){
					cellArr[i][j].solidFlag = false;
					cellArr[i][j].gotoAndStop(1);
				}
			}
			
			newShapeFlag = true;
		}
		
		private function gameEnterFrame(e:Event){
			if(newShapeFlag == true){
				cell1 = null;
				cell2 = null;
				cell3 = null;
				cell4 = null;
				
				switch(crtShapeIndex){
					case 1://T
						moveToFun(midNum, cellLineNum - 1, midNum - 1, cellLineNum - 2, midNum, cellLineNum - 2, midNum + 1, cellLineNum - 2);
					break;
					case 2://J
						moveToFun(midNum + 1, cellLineNum - 1, midNum - 1, cellLineNum - 2, midNum, cellLineNum - 2, midNum + 1, cellLineNum - 2);
					break;
					case 3://L
						moveToFun(midNum - 1, cellLineNum - 1, midNum - 1, cellLineNum - 2, midNum, cellLineNum - 2, midNum + 1, cellLineNum - 2);
					break;
					case 4://田
						moveToFun(midNum, cellLineNum - 1, midNum + 1, cellLineNum - 1, midNum, cellLineNum - 2, midNum + 1, cellLineNum - 2);
					break;
					case 6://Z
						moveToFun(midNum - 1, cellLineNum - 1, midNum, cellLineNum - 1, midNum, cellLineNum - 2, midNum + 1, cellLineNum - 2);
					break;
					case 7://S
						moveToFun(midNum + 1, cellLineNum - 1, midNum, cellLineNum - 1, midNum, cellLineNum - 2, midNum - 1, cellLineNum - 2);
					break;
					default://I
						moveToFun(midNum - 1, cellLineNum - 2, midNum, cellLineNum - 2, midNum + 1, cellLineNum - 2, midNum + 2, cellLineNum - 2);
					break;
				}
				
				crtRollIndex = 1;
				nextShapeIndex = int(Math.random() * shapeTotalNum) + 1;
				shape.gotoAndStop(nextShapeIndex);
				
				newShapeFlag = false;
				
				if(cell1.solidFlag == true || cell2.solidFlag == true || cell3.solidFlag == true || cell4.solidFlag == true){
					this.removeEventListener(Event.ENTER_FRAME, gameEnterFrame);
					gameOverFlag = true;
					endPanel.visible = true;
					endPanel.score_txt.text = game_scr;
				}
				
				return;
			}			
			
			game_enterframe_count ++;
			var lvlCount:uint;
			if(game_lvl < 5){
				lvlCount = 26 - game_lvl * 2;
			}
			else if(game_lvl < 22){
				lvlCount = 18 - game_lvl;
			}
			else{
				lvlCount = 1;
			}
			if(game_enterframe_count == lvlCount){
				var x1:uint = cell1.getXIndex();
				var y1:uint = cell1.getYIndex();
				var x2:uint = cell2.getXIndex();
				var y2:uint = cell2.getYIndex();
				var x3:uint = cell3.getXIndex();
				var y3:uint = cell3.getYIndex();
				var x4:uint = cell4.getXIndex();
				var y4:uint = cell4.getYIndex();
				
				if(checkSolid(cell1, false, 0, x1, y1 - 1) == false && checkSolid(cell2, false, 0, x2, y2 - 1) == false  
			   		&& checkSolid(cell3, false, 0, x3, y3 - 1) == false && checkSolid(cell4, false, 0, x4, y4 - 1) == false){
					moveToFun(x1, y1 - 1, x2, y2 - 1, x3, y3 - 1, x4, y4 - 1);
					game_enterframe_count = 0;
				}
				else{
					changeToSolid();
				}
			}
		}
		
		private function checkSolid(c:Cell, checkX:Boolean, staticXNum:int, aimX:int, aimY:int):Boolean{
			var cx:uint = c.getXIndex();
			var cy:uint = c.getYIndex();
			
			if(cy < 0)	return true;
			if(checkX && (cx < 0 || cx == staticXNum)) return true;
			if(aimX < 0 || aimX >= cellRowNum || aimY < 0 || aimY >= cellLineNum) return true;
			if(cellArr[aimX][aimY].solidFlag == true) return true;
			
			return false;
		}
		
		private function keyDownHandler(e:KeyboardEvent){
			if(e.keyCode == Keyboard.ENTER || e.keyCode == Keyboard.NUMPAD_ENTER){
				if(gameOverFlag){
					endPanel.visible = false;
					
					gameOverFlag = false;
					restart();
					this.addEventListener(Event.ENTER_FRAME, gameEnterFrame);
					return;
				}
				
				if(game_pause_flag == false){
					this.addEventListener(Event.ENTER_FRAME, gameEnterFrame);
					game_pause_flag = true;
					shape.visible = true;
					
					helpPanel.visible = false;
				}
				else{
					this.removeEventListener(Event.ENTER_FRAME, gameEnterFrame);
					game_pause_flag = false;
					shape.visible = false;
					
					helpPanel.visible = true;
				}
				return;
			}
			
			if(game_pause_flag == false) return;
			
			var x1:uint = cell1.getXIndex();
			var y1:uint = cell1.getYIndex();
			var x2:uint = cell2.getXIndex();
			var y2:uint = cell2.getYIndex();
			var x3:uint = cell3.getXIndex();
			var y3:uint = cell3.getYIndex();
			var x4:uint = cell4.getXIndex();
			var y4:uint = cell4.getYIndex();
			
			if(e.keyCode == Keyboard.DOWN){//down
				if(checkSolid(cell1, false, 0, x1, y1 - 1) == false && checkSolid(cell2, false, 0, x2, y2 - 1) == false && 
				   checkSolid(cell3, false, 0, x3, y3 - 1) == false && checkSolid(cell4, false, 0, x4, y4 - 1) == false){
					//move
					moveToFun(x1, y1 - 1, x2, y2 - 1, x3, y3 - 1, x4, y4 - 1);
					
					//changeToSolid();
					
					game_enterframe_count = 0;
				}
			}
			else if(e.keyCode == Keyboard.LEFT){//toLeft
				if(checkSolid(cell1, true, 0, x1 - 1, y1) == false && checkSolid(cell2, true, 0, x2 - 1, y2) == false && 
				   checkSolid(cell3, true, 0, x3 - 1, y3) == false && checkSolid(cell4, true, 0, x4 - 1, y4) == false){
					//move
					moveToFun(x1 - 1, y1, x2 - 1, y2, x3 - 1, y3, x4 - 1, y4);
					
					//changeToSolid();
				}
			}
			else if(e.keyCode == Keyboard.RIGHT){//toRight
				if(checkSolid(cell1, true, cellRowNum - 1, x1 + 1, y1) == false && 
				   checkSolid(cell2, true, cellRowNum - 1, x2 + 1, y2) == false && 
				   checkSolid(cell3, true, cellRowNum - 1, x3 + 1, y3) == false && 
				   checkSolid(cell4, true, cellRowNum - 1, x4 + 1, y4) == false){
					//move
					moveToFun(x1 + 1, y1, x2 + 1, y2, x3 + 1, y3, x4 + 1, y4);
					
					//changeToSolid();
				}
			}
			else if(e.keyCode == Keyboard.SPACE || e.keyCode == Keyboard.UP){//Space or toUp
				//roll cell
				switch(crtShapeIndex){
					case 1://T
						switch(crtRollIndex){
							case 2:
								if(!checkSolid(cell2, true, 0, x2 - 1, y2 - 1)){
									moveToFun(x1 - 1, y1 - 1, x2 + 1, y2 - 1, x3, y3, x4 - 1, y4 + 1);
					
									//changeToSolid();
					
									crtRollIndex = 3;
								}
							break;
							case 3:
								if(!checkSolid(cell2, true, 0, x2 - 1, y2 + 1)){
									moveToFun(x1 - 1, y1 + 1, x2 - 1, y2 - 1, x3, y3, x4 + 1, y4 + 1);
					
									//changeToSolid();
					
									crtRollIndex = 4;
								}
							break;
							case 4:
								if(!checkSolid(cell2, true, cellRowNum - 1, x2 + 1, y2 + 1)){
									moveToFun(x1 + 1, y1 + 1, x2 - 1, y2 + 1, x3, y3, x4 + 1, y4 - 1);
					
									//changeToSolid();
					
									crtRollIndex = 1;
								}
							break;
							default:
								if(!checkSolid(cell2, true, cellRowNum - 1, x2 + 1, y2 - 1)){
									moveToFun(x1 + 1, y1 - 1, x2 + 1, y2 + 1, x3, y3, x4 - 1, y4 - 1);
					
									//changeToSolid();
					
									crtRollIndex = 2;
								}
							break;
						}
					break;
					case 2://J
						switch(crtRollIndex){
							case 2:
								if(checkSolid(cell1, true, 0, x1 - 2, y1) == false && 
								   checkSolid(cell2, true, cellRowNum - 1, x2 + 1, y2 - 1) == false &&
								   checkSolid(cell4, true, 0, x4 - 1, y4 + 1) == false){
									moveToFun(x1 - 2, y1, x2 + 1, y2 - 1, x3, y3, x4 - 1, y4 + 1);
					
									//changeToSolid();
					
									crtRollIndex = 3;
								}
							break;
							case 3:
								if(checkSolid(cell1, false, 0, x1, y1 + 2) == false && 
								   checkSolid(cell2, true, 0, x2 - 1, y2 - 1) == false &&
								   checkSolid(cell4, true, cellRowNum - 1, x4 + 1, y4 + 1) == false){
									moveToFun(x1, y1 + 2, x2 - 1, y2 - 1, x3, y3, x4 + 1, y4 + 1);
					
									//changeToSolid();
					
									crtRollIndex = 4;
								}
							break;
							case 4:
								if(checkSolid(cell1, true, cellRowNum - 1, x1 + 2, y1) == false && 
								   checkSolid(cell2, true, 0, x2 - 1, y2 + 1) == false &&
								   checkSolid(cell4, true, cellRowNum - 1, x4 + 1, y4 - 1) == false){
									moveToFun(x1 + 2, y1, x2 - 1, y2 + 1, x3, y3, x4 + 1, y4 - 1);
					
									//changeToSolid();
					
									crtRollIndex = 1;
								}
							break;
							default:
								if(checkSolid(cell1, false, 0, x1, y1 - 2) == false && 
								   checkSolid(cell2, true, cellRowNum - 1, x2 + 1, y2 + 1) == false &&
								   checkSolid(cell4, true, 0, x4 - 1, y4 - 1) == false){
									moveToFun(x1, y1 - 2, x2 + 1, y2 + 1, x3, y3, x4 - 1, y4 - 1);
					
									//changeToSolid();
					
									crtRollIndex = 2;
								}
							break;
						}
					break;
					case 3://L
						switch(crtRollIndex){
							case 2:
								if(checkSolid(cell1, false, 0, x1, y1 - 2) == false && 
								   checkSolid(cell2, true, cellRowNum - 1, x2 + 1, y2 - 1) == false &&
								   checkSolid(cell4, true, 0, x4 - 1, y4 + 1) == false){
									moveToFun(x1, y1 - 2, x2 + 1, y2 - 1, x3, y3, x4 - 1, y4 + 1);
					
									//changeToSolid();
					
									crtRollIndex = 3;
								}
							break;
							case 3:
								if(checkSolid(cell1, true, 0, x1 - 2, y1) == false && 
								   checkSolid(cell2, true, 0, x2 - 1, y2 - 1) == false &&
								   checkSolid(cell4, true, cellRowNum - 1, x4 + 1, y4 + 1) == false){
									moveToFun(x1 - 2, y1, x2 - 1, y2 - 1, x3, y3, x4 + 1, y4 + 1);
					
									//changeToSolid();
					
									crtRollIndex = 4;
								}
							break;
							case 4:
								if(checkSolid(cell1, false, 0, x1, y1 + 2) == false && 
								   checkSolid(cell2, true, 0, x2 - 1, y2 + 1) == false &&
								   checkSolid(cell4, true, cellRowNum - 1, x4 + 1, y4 - 1) == false){
									moveToFun(x1, y1 + 2, x2 - 1, y2 + 1, x3, y3, x4 + 1, y4 - 1);
					
									//changeToSolid();
					
									crtRollIndex = 1;
								}
							break;
							default:
								if(checkSolid(cell1, true, cellRowNum - 1, x1 + 2, y1) == false && 
								   checkSolid(cell2, true, cellRowNum - 1, x2 + 1, y2 + 1) == false &&
								   checkSolid(cell4, true, 0, x4 - 1, y4 - 1) == false){
									moveToFun(x1 + 2, y1, x2 + 1, y2 + 1, x3, y3, x4 - 1, y4 - 1);
					
									//changeToSolid();
					
									crtRollIndex = 2;
								}
							break;
						}
					break;
					case 5://I
						switch(crtRollIndex){
							case 2:
								if(checkSolid(cell1, true, 0, x1 - 1, y1 - 1) == false && 
								   checkSolid(cell3, true, cellRowNum - 1, x3 + 1, y3 + 1) == false &&
								   checkSolid(cell4, true, cellRowNum - 1, x4 + 2, y4 + 2) == false){
									moveToFun(x1 - 1, y1 - 1, x2, y2, x3 + 1, y3 + 1, x4 + 2, y4 + 2);
					
									//changeToSolid();
					
									crtRollIndex = 1;
								}
							break;
							default:
								if(checkSolid(cell1, true, cellRowNum - 1, x1 + 1, y1 + 1) == false && 
								   checkSolid(cell3, true, 0, x3 - 1, y3 - 1) == false &&
								   checkSolid(cell4, true, 0, x4 - 2, y4 - 2) == false){
									moveToFun(x1 + 1, y1 + 1, x2, y2, x3 - 1, y3 - 1, x4 - 2, y4 - 2);
					
									//changeToSolid();
					
									crtRollIndex = 2;
								}
							break;
						}
					break;
					case 6://Z
						switch(crtRollIndex){
							case 2:
								if(checkSolid(cell1, true, 0, x1 - 2, y1) == false && 
								   checkSolid(cell4, false, 0, x2, y2 + 2) == false){
									moveToFun(x1 - 2, y1, x2 - 1, y2 + 1, x3, y3, x4 + 1, y4 + 1);
					
									//changeToSolid();
					
									crtRollIndex = 1;
								}
							break;
							default:
								if(checkSolid(cell1, true, cellRowNum - 1, x1 + 2, y1) == false && 
								   checkSolid(cell2, false, 0, x2, y2 - 2) == false){
									moveToFun(x1 + 2, y1, x2 + 1, y2 - 1, x3, y3, x4 - 1, y4 - 1);
					
									//changeToSolid();
					
									crtRollIndex = 2;
								}
							break;
						}
					break;
					case 7://S
						switch(crtRollIndex){
							case 2:
								if(checkSolid(cell1, false, 0, x1, y1 + 2) == false && 
								   checkSolid(cell2, true, 0, x2 - 2, y2) == false){
									moveToFun(x1, y1 + 2, x2 - 1, y2 + 1, x3, y3, x4 - 1, y4 - 1);
					
									//changeToSolid();
					
									crtRollIndex = 1;
								}
							break;
							default:
								if(checkSolid(cell1, false, 0, x1, y1 - 2) == false && 
								   checkSolid(cell4, true, cellRowNum - 1, x2 + 2, y2) == false){
									moveToFun(x1, y1 - 2, x2 + 1, y2 - 1, x3, y3, x4 + 1, y4 + 1);
					
									//changeToSolid();
					
									crtRollIndex = 2;
								}
							break;
						}
					break;
					default://田
					break;
				}
			}
		}
		
		private function changeToSolid(){
			var x1:uint = cell1.getXIndex();
			var y1:uint = cell1.getYIndex();
			var x2:uint = cell2.getXIndex();
			var y2:uint = cell2.getYIndex();
			var x3:uint = cell3.getXIndex();
			var y3:uint = cell3.getYIndex();
			var x4:uint = cell4.getXIndex();
			var y4:uint = cell4.getYIndex();
			
			if(checkSolid(cell1, false, 0, x1, y1 - 1) || checkSolid(cell2, false, 0, x2, y2 - 1) || 
			   checkSolid(cell3, false, 0, x3, y3 - 1) || checkSolid(cell4, false, 0, x4, y4 - 1)){
				cell1.solidFlag = true;
				cell2.solidFlag = true;
				cell3.solidFlag = true;
				cell4.solidFlag = true;
				
				if(isQuiet == false){
					var dropChannel:SoundChannel = dropSound.play();
					dropChannel.addEventListener(Event.SOUND_COMPLETE, dropFinishHandler);
				}
			}
		}
		
		private function moveToFun(newx1:int, newy1:int, newx2:int, newy2:int, newx3:int, newy3:int, newx4:int, newy4:int){
			if(cell1 != null && cell2 != null && cell3 != null && cell4 != null){			
			//drop
				cell1.gotoAndStop(1);
				cell2.gotoAndStop(1);
				cell3.gotoAndStop(1);
				cell4.gotoAndStop(1);
			}
			
			cell1 = cellArr[newx1][newy1];
			cell2 = cellArr[newx2][newy2];
			cell3 = cellArr[newx3][newy3];
			cell4 = cellArr[newx4][newy4];
			
			cell1.gotoAndStop(crtShapeIndex + 1);
			cell2.gotoAndStop(crtShapeIndex + 1);
			cell3.gotoAndStop(crtShapeIndex + 1);
			cell4.gotoAndStop(crtShapeIndex + 1);
		}
		
		private function checkFullLine():Boolean{
			var flag:Boolean = false;
			var plusLine:int = 0;
			for(var j:int = 0; j < cellLineNum; j ++){
				var lineFullFlag:Boolean = true;
				for(var i:int = 0; i < cellRowNum; i ++){
					if(cellArr[i][j].getIndex() == 1) lineFullFlag = false;
				}
				
				if(lineFullFlag) {
					flag = true;
					for(var m:int = 0; m < cellRowNum; m ++){
						cellArr[m][j].gotoAndStop(9);
					}
					if(isQuiet == false){
						var removeChannel:SoundChannel = removeSound.play();
						removeChannel.addEventListener(Event.SOUND_COMPLETE, removeFinishHandler);
					}
					
					plusLine ++;
					
					game_scr += plusLine * 5;
					mainPanel.score_txt.text = game_scr;
					
					if(game_scr >= 50 * game_lvl){
						game_lvl ++;
						mainPanel.level_txt.text = game_lvl;
					}
				}
				else plusLine = 0;
			}
			return flag;
		}
		
		private function goBtnHandler(e:MouseEvent){
			this.addEventListener(Event.ENTER_FRAME, gameEnterFrame);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			game_pause_flag = true;
			shape.visible = true;
			
			helpPanel.visible = false;
		}
		
		private function retryBtnHandler(e:MouseEvent){
			endPanel.visible = false;
					
			gameOverFlag = false;
			restart();
			this.addEventListener(Event.ENTER_FRAME, gameEnterFrame);
		}
		
		private function soundBtnHandler(e:MouseEvent){
			isQuiet = true;
			mainPanel.sound_btn.visible = false;
			soundChannel.stop();
		}
		
		private function quietBtnHandler(e:MouseEvent){
			isQuiet = false;
			mainPanel.sound_btn.visible = true;
			soundChannel = bgmSound.play();
		}
		
		private function dropFinishHandler(e:Event){
			if(!checkFullLine()){
				game_enterframe_count = 0;
				newShapeFlag = true;
				crtShapeIndex = nextShapeIndex;
			}
		}
		
		private function removeFinishHandler(e:Event){
			var tmpCell;
			
			for(var j:int = 0; j < cellLineNum; j ++){
				if(cellArr[0][j].getIndex() != 9) continue;
				for(var l:int = 0; l < cellRowNum; l ++){
					for(var k:int = j; k < cellLineNum - 1; k ++){
						tmpCell = cellArr[l][k];
						
						var upCell = cellArr[l][k + 1];
						tmpCell.gotoAndStop(upCell.getIndex());
						tmpCell.solidFlag = upCell.solidFlag;
					}
					
					tmpCell = cellArr[l][cellLineNum - 1];
					tmpCell.gotoAndStop(1);
					tmpCell.solidFlag = false;
				}
				j --;
			}
			
			game_enterframe_count = 0;
			newShapeFlag = true;
			crtShapeIndex = nextShapeIndex;
		}
		
		private function quitHandler(e:MouseEvent){
			fscommand("quit");
		}
	}
	
}
